﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CSharp10
{
    class ConcurrencyAndMultiThresd
    {
        public static async Task Show()
        {
            async Task Go()
            {
                await PrintAnswerToLife();
                Console.WriteLine("Done");
            }
            async Task PrintAnswerToLife()
            {
                int answer = await GetAnswerToLife();
                Console.WriteLine(answer);
            }
            async Task<int> GetAnswerToLife()
            {
                await Task.Delay(5000);
                int answer = 21 * 2;
                return answer;
            }

            await Go();
        }

        public static void Show2()
        {
            void Go()
            {
                PrintAnswerToLife();
                Console.WriteLine("Done");
            }
            void PrintAnswerToLife()
            {
                int answer = GetAnswerToLife();
                Console.WriteLine(answer);
            }
            int GetAnswerToLife()
            {
                Thread.Sleep(5000);
                int answer = 21 * 2;
                return answer;
            }

            Go();
        }

        static Dictionary<string, string> _catch = new Dictionary<string, string>();
        // 在并行方法中 最底层的方法中实例化一个 TaskComplationSource 类 来处理 IO并发，使用 Task.Run 来处理计算并发。
        public void Show3()
        {
            /*//await foreach(var number in RangeAsync(0,10,500))
            //    Console.WriteLine(number);

            //IAsyncEnumerable<int> query = from i in RangeAsync(0, 10, 500)
            //                              where i % 2 == 0
            //                              select i * 10;
            //await foreach (var num in query)
            //    Console.WriteLine(num);
            //string uri = "http://www.albahari.com";
            //string html;
            //if (_catch.TryGetValue(uri, out html)) Console.WriteLine(html);
            //html = _catch[uri] = await new WebClient().DownloadStringTaskAsync(uri);
            //Console.WriteLine(html);
            //var html = await GetWebPageAsync(uri);
            //Console.WriteLine(html);
            //Console.WriteLine("***************************");

            //foreach(var data in await RangeTaskAsync(0,10,500))
            //    Console.WriteLine(data);*/


            //var tcs = new TaskCompletionSource<int>();
            //new Thread(() => { Thread.Sleep(5000); tcs.SetResult(42); }) { IsBackground = true }.Start();
            //Task<int> task = tcs.Task;
            //Console.WriteLine(task.Result);

            /*   Task<int> task = Run(() =>
               {
                   Thread.Sleep(5000);
                   return 42;
               });

               Console.WriteLine(task.Result);*/

            /* // 使用这种方法没有阻塞任何线程
             //var awaiter = GetAnswerToLife().GetAwaiter();
             //awaiter.OnCompleted(() => Console.WriteLine(awaiter.GetResult()));
             //Console.ReadLine();

             // 测试自定义延时方法
             //Console.WriteLine("等待开始");
             //var task = Delay(3000);
             //task.Wait();
             //Console.WriteLine("等待结束了");*/

            //Delay(5000).GetAwaiter().OnCompleted(() => Console.WriteLine(42));
            for (int i = 0; i < 1000; i++)
                //Delay(5000).GetAwaiter().OnCompleted(() => Console.WriteLine(42));
                Task.Delay(5000).GetAwaiter().OnCompleted(() => Console.WriteLine(42));
            Console.ReadLine();


        }

        public async Task Show4()
        {
            Task<int> GetPrimesCountAsync(int start, int count)
            {
                return Task.Run(() => ParallelEnumerable.Range(start, count).Count(n =>
                    Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
            }

            async Task DisplayPrimeCounts()
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(await GetPrimesCountAsync(i * 1000000 + 2, 1000000) + " primes between " + (i * 1000000) + " and " + ((i + 1) * 1000000 - 1));
                }
                Console.WriteLine("Done!");
            }

            await Task.Run(async () => await DisplayPrimeCounts());
            //int result = await GetPrimesCountAsync(2, 1000000);
            //Console.WriteLine(result);
            //Console.ReadLine();

        }

        /// <summary>
        /// 使用 Timer 类可以让CLR在等待指定时间后触发事件
        /// </summary>
        /// <returns></returns>
        Task<int> GetAnswerToLife()
        {
            var tcs = new TaskCompletionSource<int>();
            var timer = new System.Timers.Timer(5000) { AutoReset = false };
            timer.Elapsed += delegate { timer.Dispose(); tcs.SetResult(42); };
            timer.Start();
            return tcs.Task;
        }

        /// <summary>
        /// 编写一个自定义的延时方法
        /// </summary>
        /// <param name="milliseconds"></param>
        /// <returns></returns>
        Task Delay(int milliseconds)
        {
            var tcs = new TaskCompletionSource();
            var timer = new System.Timers.Timer(milliseconds) { AutoReset = false };
            timer.Elapsed += delegate { timer.Dispose(); tcs.SetResult(); };
            timer.Start();
            return tcs.Task;
        }

        /// <summary>
        /// 编写自己的 Run 方法
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        Task<TResult> Run<TResult>(Func<TResult> func)
        {
            var tcs = new TaskCompletionSource<TResult>();
            new Thread(() =>
            {
                try
                {
                    tcs.SetResult(func());
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
            }).Start();
            return tcs.Task;
        }

        //async Task<string> Foo() { return "abc"; }
        //Task<string> Foo() { return Task.FromResult("abc"); }
        async Task Foo(CancellationToken cancellationToken)
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
                await Task.Delay(1000, cancellationToken);
            }
        }

        async Task<string> GetWebPageAsync(string uri)
        {
            string html;
            if (_catch.TryGetValue(uri, out html)) return html;
            return _catch[uri] = await new WebClient().DownloadStringTaskAsync(uri);
        }
        async IAsyncEnumerable<int> RangeAsync(int start, int count, int delay)
        {
            for (int i = start; i < start + count; i++)
            {
                await Task.Delay(delay);
                yield return i;
            }
        }

        async Task<IEnumerable<int>> RangeTaskAsync(int start, int count, int delay)
        {
            List<int> data = new List<int>();
            for (int i = start; i < start + count; i++)
            {
                await Task.Delay(delay);
                data.Add(i);
            }

            return data;
        }


        public async Task Show5()
        {
            /*Task Foo(Action<int> onProgressPercentChanged)
            {
                return Task.Run(async () =>
                {
                    for (int i = 0; i < 1000; i++)
                    {
                        if (i % 10 == 0) onProgressPercentChanged(i / 10);
                        await Task.Delay(10);
                    }
                });
            }

            await Foo(i => Console.WriteLine(i + " %"));
*/
            /*Task Foo(IProgress<int> onProgressPercentChanged)
            {
                return Task.Run(async () =>
                {
                    for (int i = 0; i < 1000; i++)
                    {
                        if (i % 10 == 0) onProgressPercentChanged.Report(i / 10);
                        await Task.Delay(10);
                    }
                });
            }
            //var progress = new Progress<int>(i => Console.WriteLine(i + " %"));
            //await Foo(progress);
            var progress = new Progress<int>();
            progress.ProgressChanged += Progress_ProgressChanged;
            await Foo(progress);*/

            async Task<int> Delay1() { await Task.Delay(1000);return 1; }
            async Task<int> Delay2() { await Task.Delay(2000); return 2; }
            async Task<int> Delay3() { await Task.Delay(3000); return 3; }
            Task<int> winningTask = await Task.WhenAny(Delay1(),Delay2(),Delay3());
            Console.WriteLine("Done");
            Console.WriteLine(await winningTask);
            int answer = await await Task.WhenAny(Delay1(), Delay2(), Delay3());
            Console.WriteLine(answer);

        }

        private void Progress_ProgressChanged(object? sender, int e)
        {
            Console.WriteLine(e + " %");
        }
    }
}
